package org.refresh.prolog;

import java.io.File;
import java.io.FileWriter;
import java.util.Hashtable;

import org.refresh.prolog.dist.swi.JPLEngine;

public class Prolog {
	
	private File logFile_;
	private FileWriter logWriter_;

	private class QueryRunner implements Runnable {
		private PrologQuery query_;

		public QueryRunner(PrologQuery q) {
			query_ = q;
		}

		public void run() {
			boolean solved = query_.hasMoreSolutions();
			solved(solved);
		}
	}
	
	public void log(String l){
		if(logFile_ != null){
			try{
				logWriter_.write(":-"+l+"\n");
				logWriter_.flush();
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public void setLogFile(File f){
		logFile_ = f;
		if(f != null){
			try{
				logWriter_ = new FileWriter(f);
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private synchronized void executeQuery(PrologQuery q, long timeout) {
		solved_ = false;
		QueryRunner runner = new QueryRunner(q);
		Thread t = new Thread(runner);
		t.start();
		try {
			if (timeout > 0) {
				wait(timeout);
			} else {
				wait();
			}
		} catch (Exception e) {
		}
	}

	private static PrologEngine engine_;

	private boolean useThread_ = true;

	private PrologQuery iCurrent_;

	private boolean solved_;

	public PrologEngine getPrologEngine() {
		if (engine_ == null) {
			engine_ = new JPLEngine();
			//engine_ = new InterPrologEngine();
			// try{
			// Object[] ext = PluginUtilities.loadExtensions("*",
			// PrologEngine.EXTENSION_POINT);
			// if(ext.length > 0){
			// engine_ = (PrologEngine)ext[0];
			// }
			// }catch (Exception e) {
			// e.printStackTrace();
			// }
		}
		return engine_;
	}

	public void abort() {
		iCurrent_.close();
	}

	public void close() {
		if (iCurrent_ != null)
			iCurrent_.close();
	}

	public Hashtable nextSolution() {
		return iCurrent_.nextSolution();
	}

	public boolean hasSolution() {
		return iCurrent_.hasSolution();
	}

	public boolean hasMoreSolutions() {
		try {
			return iCurrent_.hasMoreSolutions();
		} catch (Throwable e) {
			e.printStackTrace();
		}
		return false;
	}

	public Hashtable executeQuery(long timeout) {
		executeQuery(iCurrent_, timeout);
		if (solved_) {
			return iCurrent_.nextSolution();
		}
		return null;
	}

	public boolean query(String q) {
		try {
			log(q);
			//System.out.println("Executing query:" + q);

			iCurrent_ = getPrologEngine().createQuery(q, null);
			// query.query();
			// if(query.hasMoreSolutions()){
			// return true;
			// }
			long start = System.currentTimeMillis();
			if (iCurrent_.hasMoreSolutions()) {
				long total = System.currentTimeMillis() - start;
				//System.out.println("Initial time:"+total);
				return true;
			}
			return false;

		} catch (Throwable e) {
			e.printStackTrace();
		}
		return false;
	}

	public void setQuery(String q, String[] vars) {
		iCurrent_ = getPrologEngine().createQuery(q, vars);
	}

	public boolean consult(File f) {
		String libloc = f.getAbsolutePath();
		libloc = libloc.replaceAll("\\\\", "/");
		//System.out.println("consult('"+libloc+"').");
		String query = "consult('"+libloc+"').";
		log(query);
		return getPrologEngine().consult(f);
	}

	public boolean reConsult(File f) {
		return getPrologEngine().reConsult(f);
	}

	private synchronized void solved(boolean solved) {
		solved_ = solved;
		notifyAll();
	}

}
